#ifndef __COPTR__
#define __COPTR__

namespace xm
{
	template < class I>
	struct iptr
	{
	private:
		I * ptr;
		
	public:

		iptr() : ptr(0) {}

		//iptr( iptr & r ) : ptr(0) { take(r.ptr); };

		iptr( const iptr & r ) : ptr(0) { take((I*)r.ptr); };

		iptr( IUnknown * up ) : ptr(0) { take( up ); }

		template < class K>
		iptr( iptr<K>& up ) : ptr(0) { take( up.p() ); }

		iptr( PROGID tClsid, IUnknown * outer = 0, IUnknown * xt = 0 ) : ptr(0) { XmCreateInstance( tClsid, outer, uuidof(I), vpp(), xt ); }

		iptr( FileType fmt, IUnknown * outer = 0, IUnknown * xt = 0 ) : ptr(0) { XmCreateArchive( fmt, outer, uuidof(I), vpp(), xt ); }

		~iptr() { dispose(); }

		iptr& operator = ( iptr& r ) { take( r.p() ); return *this; }

		iptr& operator = ( IUnknown * up ) { take( up ); return *this; }

		template < class K>
		iptr& operator = ( iptr<K>& up ) { take( up.p() ); return *this; }

		void take( IUnknown * ip ) 
		{
			dispose();
			if( !ip ) return;
			void * _vp = 0;
			HRESULT hr = ip->QueryInterface( uuidof(I), &_vp );
			if( hr < 0 ) return ;
			ptr = (I*)_vp;
		}
		void dispose() { if(!ptr) return; ptr->Release(); ptr = 0; }

		I* detach() { I* ret = ptr; ptr = 0; return ret; }

		operator I * () { return ptr; }

		I* operator -> () { return ptr; }

		HRESULT instantiation( PROGID tClsid, IUnknown * outer = 0, IUnknown * xt = 0 )
		{
			dispose();
			return XmCreateInstance( tClsid, outer, uuidof(I), vpp(), xt );
		}
		HRESULT instantiation( FileType type, IUnknown * outer = 0, IUnknown * xt = 0 )
		{
			dispose();
			return XmCreateArchive( type, outer, uuidof(I), vpp(), xt );
		}
		I* p(){ return ptr; };
		I** pp() { return &ptr; };
		void** vpp() { return (void**)&ptr; };
	};

	template < class O >
	class optr
	{
	private:
		O * ptr;
	public:
		optr() : ptr(0) {}

		optr( O * p ) : ptr(0) { take(p); }

		//optr( optr & r ) : ptr(0) { take(r.ptr); };

		explicit optr( const optr & r ) : ptr(0) { take(r.ptr); };

		template < class K>
		optr( optr<K>& up ) : ptr(0) { take( up.p() ); }

		~optr() { dispose(); }

		optr& operator = ( optr& r ) { take( r.p() ); return *this; }

		optr& operator = ( O * up ) { take( up ); return *this; }

		void take( O * ip ) 
		{
			dispose();
			if( !ip ) return;
			ptr = ip;
			ptr->AddRef();
		}
		void dispose() { if(!ptr) return; ptr->Release(); ptr = 0; }

		O* detach() { I* ret = ptr; ptr = 0; return ret; }

		operator O * () { return ptr; }

		O* operator -> () { return ptr; }

		O* p(){ return ptr; };
		O** pp() { return &ptr; };

		template< class I>
		I * ip() { return (I*)ptr; };
	};

};

#endif